home *** CD-ROM | disk | FTP | other *** search
- /* date - Display (or set) the date and time Author: V. Archer */
-
- #include <sys/types.h>
- #include <ctype.h>
- #include <stddef.h>
- #include <stdlib.h>
- #include <time.h>
- #include <string.h>
- #include <unistd.h>
-
- #define MIN 60L /* # seconds in a minute */
- #define HOUR (60 * MIN) /* # seconds in an hour */
- #define DAY (24 * HOUR) /* # seconds in a day */
- #define YEAR (365 * DAY) /* # seconds in a (non-leap) year */
-
- int qflag, uflag, sflag;
-
- /* Default output file descriptor.
- */
- int outfd = 1;
-
- int main (int argc, char **argv);
- void putchar (int c);
- void pstring (char *s, int len);
- void pldecimal (unsigned long d, int digits);
- void pdecimal (int d, int digits);
- void fmtdate (char *format, time_t t, struct tm *p);
- time_t make_time (char *t);
- void usage (void);
-
- /* Main module. Handles P1003.2 date and system administrator's date. The
- * date entered should be given GMT, regardless of the system's TZ!
- */
- int main(argc, argv)
- /* [<][>][^][v][top][bottom][index][help] */
- int argc;
- char **argv;
- {
- time_t t;
- char *format;
- char time_buf[40];
- int n;
- int i;
-
- time(&t);
-
- i = 1;
- while (i < argc && argv[i][0] == '-') {
- char *opt = argv[i++] + 1, *end;
-
- if (opt[0] == '-' && opt[1] == 0) break;
-
- while (*opt != 0) switch (*opt++) {
- case 'q':
- qflag = 1;
- break;
- case 's':
- sflag = 1;
- break;
- case 'u':
- uflag = 1;
- break;
- case 't':
- if (*opt == 0) {
- if (i == argc) usage();
- opt = argv[i++];
- }
- t = strtoul(opt, &end, 10);
- if (*end != 0) usage();
- opt = "";
- break;
- }
- }
-
- if (!qflag && i < argc && ('0' <= argv[i][0] && argv[i][0] <= '9')) {
- t = make_time(argv[i++]);
- sflag = 1;
- }
-
- format = "%c";
- if (i < argc && argv[i][0] == '+') format = argv[i++] + 1;
-
- if (i != argc) usage();
-
- if (qflag) {
- pstring("\nPlease enter date: MMDDYYhhmmss. Then hit the RETURN key.\n", -1);
- n = read(0, time_buf, sizeof(time_buf));
- if (n > 0 && time_buf[n-1] == '\n') n--;
- if (n >= 0) time_buf[n] = 0;
- t = make_time(time_buf);
- sflag = 1;
- }
- if (sflag)
- {
- pstring("Amiga version: use the time command\n", -1);
- return(1);
- }
-
- /* if (sflag && stime(&t) != 0) {
- outfd = 2;
- pstring("No permission to set time\n", -1);
- return(1);
- }*/
-
- fmtdate(format, t, uflag ? gmtime(&t) : localtime(&t));
- putchar('\n');
- return(0);
- }
-
- /* Replacement for stdio putchar().
- */
- /*void putchar(c)
- int c;
- {
- static char buf[1024];
- static char *bp = buf;
-
- if (c != 0) *bp++ = c;
- if (c == 0 || c == '\n' || bp == buf + sizeof(buf)) {
- write(outfd, buf, bp - buf);
- bp = buf;
- }
- }
- */
-
- /* Internal function that prints a n-digits number. Replaces stdio in our
- * specific case.
- */
- void pldecimal(d, digits)
- /* [<][>][^][v][top][bottom][index][help] */
- unsigned long d;
- int digits;
- {
- digits--;
- if (d > 9 || digits > 0) pldecimal(d / 10, digits);
- putchar('0' + (d % 10));
- }
-
- void pdecimal(d, digits)
- /* [<][>][^][v][top][bottom][index][help] */
- int d, digits;
- {
- pldecimal((unsigned long) d, digits);
- }
-
- /* Internal function that prints a fixed-size string. Replaces stdio in our
- * specific case.
- */
- void pstring(s, len)
- /* [<][>][^][v][top][bottom][index][help] */
- char *s;
- int len;
- {
-
- while ((*s)!='\0')
- if (len--)
- {putchar(*s);s++;}
- else
- break;
- }
-
- /* Format the date, using the given locale string. A special case is the
- * TZ which might be a sign followed by four digits (New format time zone).
- */
- void fmtdate(format, t, p)
- /* [<][>][^][v][top][bottom][index][help] */
- char *format;
- time_t t;
- struct tm *p;
- {
- int i;
- char *s;
- static char *wday[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
- "Thursday", "Friday", "Saturday"};
- static char *month[] = {"January", "February", "March", "April",
- "May", "June", "July", "August",
- "September", "October", "November", "December"};
-
- p= uflag ? gmtime(&t) : localtime(&t);
-
- while (*format)
- if (*format == '%') {
- switch (*++format) {
- case 'A':
- pstring(wday[p->tm_wday], -1);
- break;
- case 'B':
- pstring(month[p->tm_mon], -1);
- break;
- case 'D':
- pdecimal(p->tm_mon + 1, 2);
- putchar('/');
- pdecimal(p->tm_mday, 2);
- putchar('/');
- case 'y':
- pdecimal(p->tm_year % 100, 2);
- break;
- case 'H':
- pdecimal(p->tm_hour, 2);
- break;
- case 'I':
- i = p->tm_hour % 12;
- pdecimal(i ? i : 12, 2);
- break;
- case 'M':
- pdecimal(p->tm_min, 2);
- break;
- case 'X':
- case 'T':
- pdecimal(p->tm_hour, 2);
- putchar(':');
- pdecimal(p->tm_min, 2);
- putchar(':');
- case 'S':
- pdecimal(p->tm_sec, 2);
- break;
- case 'U':
- pdecimal((p->tm_yday - p->tm_wday + 13) / 7, 2);
- break;
- case 'W':
- if (--(p->tm_wday) < 0) p->tm_wday = 6;
- pdecimal((p->tm_yday - p->tm_wday + 13) / 7, 2);
- if (++(p->tm_wday) > 6) p->tm_wday = 0;
- break;
- case 'Y':
- pdecimal(p->tm_year + 1900, 4);
- break;
- case 'Z':
- if (uflag) {
- s = "GMT";
- } else {
- s = (p->tm_isdst == 1) ? tzname[1] : tzname[0];
- }
- pstring(s, strlen(s));
- break;
- case 'a':
- pstring(wday[p->tm_wday], 3);
- break;
- case 'b':
- case 'h':
- pstring(month[p->tm_mon], 3);
- break;
- case 'c':
- if (!(s = getenv("LC_TIME")))
- s = "%a %b %e %T %Z %Y";
- fmtdate(s, t, p);
- break;
- case 'd':
- pdecimal(p->tm_mday, 2);
- break;
- case 'e':
- if (p->tm_mday < 10) putchar(' ');
- pdecimal(p->tm_mday, 1);
- break;
- case 'j':
- pdecimal(p->tm_yday + 1, 3);
- break;
- case 'm':
- pdecimal(p->tm_mon + 1, 2);
- break;
- case 'n': putchar('\n'); break;
- case 'p':
- if (p->tm_hour < 12)
- putchar('A');
- else
- putchar('P');
- putchar('M');
- break;
- case 'r':
- fmtdate("%I:%M:%S %p", t, p);
- break;
- case 's':
- pldecimal((unsigned long) t, 0);
- break;
- case 't': putchar('\t'); break;
- case 'w':
- putchar('0' + p->tm_wday);
- break;
- case 'x':
- fmtdate("%B %e %Y", t, p);
- break;
- case '%': putchar('%'); break;
- case '\0': format--;
- }
- format++;
- } else
- putchar(*format++);
- }
-
- /* Convert a local date string into GMT time in seconds. */
- time_t make_time(t)
- /* [<][>][^][v][top][bottom][index][help] */
- char *t;
- {
- struct tm tm; /* user specified time */
- time_t now; /* current time */
- int leap; /* current year is leap year */
- int i; /* general index */
- int fld; /* number of fields */
- int f[6]; /* time fields */
- static int days_per_month[2][12] = {
- { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
- { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }};
-
- /* Get current time just in case */
- now = time((time_t *) 0);
- tm = *localtime(&now);
- tm.tm_sec = 0;
- tm.tm_mon++;
- tm.tm_year %= 100;
-
- /* Parse the time */
- #if '0'+1 != '1' || '1'+1 != '2' || '2'+1 != '3' || '3'+1 != '4' || \
- '4'+1 != '5' || '5'+1 != '6' || '6'+1 != '7' || '7'+1 != '8' || '8'+1 != '9'
- << Code unsuitable for character collating sequence >>
- #endif
-
- for (fld = 0; fld < sizeof(f)/sizeof(f[0]); fld++) {
- if (*t == 0) break;
- f[fld] = 0;
- for (i = 0; i < 2; i++, t++) {
- if (*t < '0' || *t > '9') usage();
- f[fld] = f[fld] * 10 + *t - '0';
- }
- }
-
- switch (fld) {
- case 2:
- tm.tm_hour = f[0]; tm.tm_min = f[1]; break;
-
- case 3:
- tm.tm_hour = f[0]; tm.tm_min = f[1]; tm.tm_sec = f[2];
- break;
-
- case 5:
- tm.tm_mon = f[0]; tm.tm_mday = f[1]; tm.tm_year = f[2];
- tm.tm_hour = f[3]; tm.tm_min = f[4];
- break;
-
- case 6:
- tm.tm_mon = f[0]; tm.tm_mday = f[1]; tm.tm_year = f[2];
- tm.tm_hour = f[3]; tm.tm_min = f[4]; tm.tm_sec = f[5];
- break;
-
- default:
- usage();
- }
-
- /* Convert the time into seconds since 1 January 1970 */
- if (tm.tm_year < 70)
- tm.tm_year += 100;
- leap = (tm.tm_year % 4 == 0 && tm.tm_year % 400 != 0);
- if (tm.tm_mon < 1 || tm.tm_mon > 12 ||
- tm.tm_mday < 1 || tm.tm_mday > days_per_month[leap][tm.tm_mon-1] ||
- tm.tm_hour > 23 || tm.tm_min > 59) {
- outfd = 2;
- pstring("Illegal date format\n", -1);
- exit(1);
- }
-
- /* Convert the time into Minix time - zone independent code */
- {
- time_t utctime; /* guess at unix time */
- time_t nextbit; /* next bit to try */
- int rv; /* result of try */
- struct tm *tmp; /* local time conversion */
-
- #define COMPARE(a,b) ((a) != (b)) ? ((a) - (b)) :
- /* [<][>][^][v][top][bottom][index][help] */
-
- utctime = 1;
- do {
- nextbit = utctime;
- utctime = nextbit << 1;
- } while (utctime >= 1);
-
- for (utctime = 0; ; nextbit >>= 1) {
-
- utctime |= nextbit;
- tmp = localtime(&utctime);
- if (tmp == 0) continue;
-
- rv = COMPARE(tmp->tm_year, tm.tm_year)
- COMPARE(tmp->tm_mon + 1, tm.tm_mon)
- COMPARE(tmp->tm_mday, tm.tm_mday)
- COMPARE(tmp->tm_hour, tm.tm_hour)
- COMPARE(tmp->tm_min, tm.tm_min)
- COMPARE(tmp->tm_sec, tm.tm_sec)
- 0;
-
- if (rv > 0)
- utctime &= ~nextbit;
- else if (rv == 0)
- break;
-
- if (nextbit == 0) {
- uflag = 1;
- outfd = 2;
- pstring("Inexact conversion to UTC from ", -1);
- fmtdate("%c\n", utctime, localtime(&utctime) );
- exit(1);
- }
- }
- return utctime;
- }
- }
-
- /* (Extended) Posix prototype of date. */
- void usage()
- /* [<][>][^][v][top][bottom][index][help] */
- {
- outfd = 2;
- pstring("Usage: date [-qsu] [-t seconds] [[MMDDYY]hhmm[ss]] [+format]\n", -1);
- exit(1);
- }
- /* [<][>][^][v][top][bottom][index][help] */
-